/** ***********************************************************************************
* @file         agnss_task.c
* @brief        AGNSS数据基础管理任务
* @details      主要用来辅助GNSS在首次定位时，快速定位；
* @author       杨小珛
* @date         2021/06/02
* @copyright    北京高知科技有限公司    
* @version      V1.0
* @attention    无
**************************************************************************************/
#include "agnss_task.h"
#include "mon_task.h"
#include "log_task.h"
#include "power_task.h"
#include "net_socket_api.h"
#include "rtc_task.h"
#include "gnss_task.h"

agnss_server_data_t agnss_server_data;            /*agnss 服务器快速定位的数据*/

static void agnss_data_handle_task( void * pvParameters );
static void agnss_net_run_para_init( void );

/** ****************************************************************************
* @remarks       static void agnss_net_run_para_init( void )
* @brief         AGNSS 网络运行参数初始化
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     在系统启动后进行创建
*******************************************************************************/
static void agnss_net_run_para_init( void )
{
	memset((uint8_t *)&agnss_server_data , 0x00 , sizeof(agnss_server_data_t));
    /*创建AGNSS 服务器数据 空间地址*/
    agnss_server_data.buf  = (uint8_t *)gaoz_fibo_malloc( AGNSS_SERVER_DATA_LEN );
    memset((uint8_t *)agnss_server_data.buf, 0x00 , AGNSS_SERVER_DATA_LEN);
    if( agnss_server_data.buf == NULL )
    {
        while(1); /*创建失败*/
    }
}

/** ****************************************************************************
* @remarks       void agnss_data_create_task( unsigned portBASE_TYPE uxPriority )
* @brief         创建AGNSS基层数据管理任务
* @param[in]     uxPriority任务优先级；
* @param[out]    无
* @return        无
* @attention     在系统启动后进行创建
*******************************************************************************/
void agnss_data_create_task( unsigned portBASE_TYPE uxPriority )
{   
    agnss_net_run_para_init();
    gaoz_thread_create(agnss_data_handle_task, AGPS_MAN_NAME, 1024*4, NULL, uxPriority);
}

/** ****************************************************************************
* @remarks       uint32_t agnss_ephemeris_data_set( void )
* @brief         AGNSS 通过串口发送星历数据
* @param[in]     无
* @param[out]    无
* @return        pdPASS 设置成功  pdFAIL 设置失败
* @attention     无
*******************************************************************************/
uint32_t agnss_ephemeris_data_set( void )
{   
#if 1
    uint32_t ret = pdFAIL, package = 0, postion = 0, i = 0;
      
      log_debug_printf( INFOR_MODE,AGPS_MAN_NAME ,"agnss_server_data.len=%d\r\n",agnss_server_data.len );
    if( agnss_server_data.type == AGNSS_SERVER_UPDATA )
    {
        package = agnss_server_data.len / 1024;
        

        for( i = 0; i < package; i ++ )
        {
            gaoz_hal_uart_put( GNSS_UART_PORT, (uint8_t *)&agnss_server_data.buf[postion], 1024 );
            postion += 1024; 
        }
        package = agnss_server_data.len % 1024;
        if( package != 0 )
        {
            gaoz_hal_uart_put( GNSS_UART_PORT, (uint8_t *)&agnss_server_data.buf[postion], package );
            postion += package;
            log_debug_printf( INFOR_MODE,AGPS_MAN_NAME ,"if( package != 0 )  package=%d\r\n",package );
        }
        
                        
        agnss_server_data.type = AGNSS_SERVER_READ;
        ret = pdPASS;
    }
#else
    uint32_t ret = pdFAIL;
    if( agnss_server_data.type == AGNSS_SERVER_UPDATA )
    {
        gaoz_hal_uart_put( GNSS_UART_PORT, (uint8_t *)agnss_server_data.buf, agnss_server_data.len );
        agnss_server_data.type = AGNSS_SERVER_READ;
        ret = pdPASS;
    }
#endif
    return ret;
}

/** ****************************************************************************
* @remarks       agnss_location_type_e agnss_location_st_get( void )
* @brief         AGNSS 定位状态获取
* @param[in]     无
* @param[out]    无
* @return        返回AGNSS 辅助定位的状态
* @attention     无
*******************************************************************************/
agnss_location_type_e agnss_location_st_get( void )
{
    agnss_location_type_e loc_st = AGNSS_LOC_INIT;
    
    if(( agnss_server_data.type == AGNSS_SERVER_UPDATA ) || ( agnss_server_data.type == AGNSS_SERVER_READ ))
    {
        loc_st = AGNSS_LOC_DATA_SUC;
    }
    else if( agnss_server_data.type == AGNSS_SERVER_FINSH )
    {
        loc_st = AGNSS_LOC_SET_SUC;
    }
    else if( agnss_server_data.type == AGNSS_SERVER_ERR )
    {
        loc_st = AGNSS_LOC_DATA_ERR;
    }
    
    return loc_st;
}

/** ****************************************************************************
* @remarks       uint32_t agnss_data_timestamp_set( void )
* @brief         AGNSS 设置 星历的时间戳
* @param[in]     mode 设置模式 
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void agnss_data_timestamp_set( agnss_timestamp_type_e mode )
{   
    if( mode == AGNSS_RUN_TIMESTAMP )
    {   
        rtc_sys_get( RTC_TIM_TIMESTAMP, (uint32_t *)&agnss_server_data.run_timestamp );
    }
    else if( mode == AGNSS_SLEEP_TIMESTAMP )
    {
        rtc_sys_get( RTC_TIM_TIMESTAMP, (uint32_t *)&agnss_server_data.sleep_timestamp );
    }
}

/** ****************************************************************************
* @remarks       static void agnss_data_handle_task( void * pvParameters )
* @brief         AGNSS基础数据处理任务
* @param[in]     * pvParameters 任务参数
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void agnss_data_handle_task( void * pvParameters )
{
    #define AGPS_SERVER_ERR_TIME    ( 60 * GAOZ_TICK_PERIOD_S )//连接AGNSS服务错误的重连时间
    #define AGPS_DATA_UPDATA_TIME   ( 300 * GAOZ_TICK_PERIOD_S )//灌入数据后 未定位 重新灌入上次下载数据的时间
    #define TD_AGPS_INIT_DATA_TIME      ( 180 * GAOZ_TICK_PERIOD_S )//重新下载 AGNSS数据的时间
    #define AGPS_AGAIG_INPUT_DATA_TIME  ( 15 * GAOZ_TICK_PERIOD_S )// 连续灌入4次 每次的间隔时间
    ( void ) pvParameters;
    uint32_t socketid = 0 ;
    int32_t recv_len = 0;
    uint8_t *recv_buf = NULL;
    uint8_t recv_time = 0;
    fd_set readfds;
    fd_set errorfds;
	fd_set writeset;
    struct timeval tv;
    int32_t ret = -1;
    uint32_t    agnss_init_time = 0;
    uint32_t    agnss_server_err_time = 0;
    uint32_t    agnss_updata_finish_time = 0;
    uint8_t agps_init_flag = 1;
    uint8_t sys_gps = 0;

    mon_reg_task_dog( 60 * GAOZ_TICK_PERIOD_S ,(uint8_t *)AGPS_MAN_NAME , TASK_SEM_YES );            /*注册任务看门狗*/
    log_debug_send( DEBUG_MODE,AGPS_MAN_NAME ,"AGNSS management task started successfully\r\n",0 );
    for(;;)
    {   
        mon_reset_task_dog();
        if( agnss_server_data.type == AGNSS_SERVER_INIT )
        {
            if( socket_free_connect( AGNSS_TAIDOU_HOST, AGNSS_TAIDOU_PORT ,e_socket_protocol_tcp , &socketid ) == pdPASS )
            {
                recv_buf = gaoz_malloc_mem( AGNSS_SERVER_DATA_LEN + 8 );
                if( recv_buf == NULL )
                {
                    socket_free_close( socketid , e_socket_protocol_tcp );
                    gaoz_task_sleep( 5000 );
                    continue;
                }
                memset( ( uint8_t * )recv_buf , 0x00 , AGNSS_SERVER_DATA_LEN );
                memset((uint8_t *)agnss_server_data.buf, 0x00 , AGNSS_SERVER_DATA_LEN);
                log_debug_send( INFOR_MODE,AGPS_MAN_NAME ,"AGNSS server connected successfully\r\n",0 );
                gaoz_task_sleep(  100 );
                recv_len = 0;
                agnss_server_data.len = 0;
                recv_time = 0;
                if( socket_free_write( socketid , ( uint8_t *)AGNSS_TAIDOU_SEND_DATA , sizeof( AGNSS_TAIDOU_SEND_DATA )) == pdPASS )
                {
                    while( 1 )
                    {
                        FD_ZERO(&readfds);FD_ZERO(&errorfds);FD_ZERO(&writeset);
                        FD_SET(socketid, &writeset);FD_SET(socketid, &readfds);FD_SET(socketid, &errorfds);
                        tv.tv_sec  = 2; 
                        tv.tv_usec = 0;
                        ret = fibo_sock_lwip_select( socketid+1, &readfds, NULL, &errorfds, &tv );
                        if( ret == 0 )
                        {
                            recv_time++;
                            gaoz_task_sleep(  100 );
                            log_debug_printf( INFOR_MODE,AGPS_MAN_NAME ,"AGNSS fibo_sock_lwip_select ret=%d recv_time=%d \r\n",ret,recv_time );
                        
                            if( recv_time >= 5 )
                            {
                                recv_time = 0; 
                                break;
                            }
                        }
                        else if( ret < 0 )
                        {
                            break;
                        }
                        else
                        {
                            if(FD_ISSET(socketid, &errorfds))	
                    		{
                    			break;
                    		}
                    		else if(FD_ISSET(socketid, &readfds))
                    		{
                                recv_len = socket_free_recv( socketid ,( uint8_t *)recv_buf , NET_RECV_DATA_LEN ); 
                                recv_len += socket_free_recv( socketid ,( uint8_t *)&recv_buf[recv_len] , NET_RECV_DATA_LEN ); 
                                recv_len += socket_free_recv( socketid ,( uint8_t *)&recv_buf[recv_len] , NET_RECV_DATA_LEN ); 
                                if( recv_len > 0  )
                                {
                                    if(( recv_len + agnss_server_data.len ) >= AGNSS_SERVER_DATA_LEN )
                                    {
                                        break;
                                    }
                                    memcpy( ( uint8_t * )&agnss_server_data.buf[agnss_server_data.len] , recv_buf , recv_len );
                                    agnss_server_data.len += recv_len;
                                    if( agnss_server_data.len  >= AGNSS_SERVER_DATA_LEN )
                                    {   
                                        agnss_server_data.len = AGNSS_SERVER_DATA_LEN;
                                        break;
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }   
                        }
                    }
                    gaoz_free_mem( ( void *)recv_buf );
                    socket_free_close( socketid , e_socket_protocol_tcp );
                    if( agnss_server_data.len != 0 )
                    {   
                        log_debug_printf( INFOR_MODE,AGPS_MAN_NAME ,"AGNSS server data read successfully,date len=%d\r\n",agnss_server_data.len );
                        agnss_server_data.type = AGNSS_SERVER_UPDATA;
                    #if( OS_GNSS_MODULE_TYPE == 1 ) 
                        agnss_server_data.couter = 0;
                        agnss_data_timestamp_set( AGNSS_RUN_TIMESTAMP );
                    #else
                        if( agnss_ephemeris_data_set() == pdPASS )
                        {
                            log_debug_send(INFOR_MODE , AGPS_MAN_NAME ,"AGNSS quick location setup successful" ,0 );
                        }
                    #endif
                    }
                    else
                    {
                        agnss_server_data.type = AGNSS_SERVER_ERR;
                        agnss_server_err_time  = gaoz_get_systick();
                        log_debug_printf( ERROR_MODE,AGPS_MAN_NAME ,"[%s]AGNSS server data read failed\r\n",sys_err_infor_pointer_get( 21 ) );
                    }

                    agnss_init_time = gaoz_get_systick();
                }
            }
            else
            {   
                gaoz_task_sleep( 5000 );
            }
        }
        else
        {   
            #if 0
            sys_gps = sys_hard_state_get(SYS_GPS);
                      
            if((sys_gps != SYS_GPS_NORMAL) && ( sys_gps != SYS_GPS_POS_OK ))
            {
                if( sys_switch_state_get( SYS_KL15 ) == SYS_KL15_HIGH )//GNSS 未定位 3min A一次
                {
                    if( pdPASS == sys_timestamp_delay(( uint32_t * )&agnss_init_time, (TD_AGPS_INIT_DATA_TIME) ))
                    {
                        log_debug_send(INFOR_MODE , AGPS_MAN_NAME ,"AGNSS position Timeout ,reset_init" ,0 );
                        agnss_server_data.type = AGNSS_SERVER_INIT;
                    } 
                }
            }  
            #endif
            #if 0//中科微的在下面走该逻辑
             /*判断GNSS停止、运行时的时间戳是否相差2个小时，如果大于2个小时重新获取AGNSS服务器星历数据*/
            if(( agnss_server_data.run_timestamp != 0 ) && (   agnss_server_data.sleep_timestamp != 0 ))
            {
                if( agnss_server_data.run_timestamp > agnss_server_data.sleep_timestamp )
                {
                    if(( agnss_server_data.run_timestamp - agnss_server_data.sleep_timestamp ) > AGNDD_DATA_MAX_TIMESTAMP )
                    {
                        agnss_server_data.run_timestamp = 0;
                        agnss_server_data.sleep_timestamp = 0;
                        agnss_server_data.type = AGNSS_SERVER_INIT;
                        continue;
                    }
                }
            }
            #endif
            gaoz_task_sleep( 1000 );
        }
    #if( OS_GNSS_MODULE_TYPE == 1 ) /*选择GNSS型号为中科微，通信波特率为115200*/
        /*当AGPS定位数据获取成功后检测GPS定位是否成功，等待10S没有成功时再次灌入AGPS数据。防止一次性灌入失败，连续三次。*/
        if( gnss_status_get() != GPS_MODEL_POSI_OK ) 
        {
            switch ( agnss_server_data.type )
            {
                case AGNSS_SERVER_UPDATA:
                    agnss_ephemeris_data_set();
                    agnss_server_data.type = AGNSS_SERVER_READ;
                    agnss_server_data.again_timestamp = gaoz_get_systick();
                    log_debug_send(INFOR_MODE , AGPS_MAN_NAME ,"AGNSS quick location setup successful" ,0 );
                break;
                case AGNSS_SERVER_READ:
                    if( gnss_agps_num_get() > GNSS_AGPS_NUM )
                    {
                        log_debug_printf(DEBUG_MODE , AGPS_MAN_NAME ,"----Agnss_info_now.gnss_position_info.sat_num = %d \r\n" ,gnss_agps_num_get());
                           
                        log_debug_send(INFOR_MODE , AGPS_MAN_NAME ,"agnss_server_data.type = AGNSS_SERVER_FINSH;" ,0 );
                       agnss_server_data.type = AGNSS_SERVER_FINSH;
                       agnss_updata_finish_time = gaoz_get_systick();
                    }
                    else
                    {
                        if( pdPASS == sys_timestamp_delay(( uint32_t * )&agnss_server_data.again_timestamp, AGPS_AGAIG_INPUT_DATA_TIME ) )
                        {
                             log_debug_send(INFOR_MODE , AGPS_MAN_NAME ," if( pdPASS == sys_timestamp_delay(( uint32_t * )&agnss_server_data.again_timestamp, AGPS_AGAIG_INPUT_DATA_TIME ) )" ,0 );
                            agnss_server_data.type = AGNSS_SERVER_UPDATA;
                            agnss_server_data.couter++;
                            if( agnss_server_data.couter > 3 )
                            {
                                agnss_server_data.type = AGNSS_SERVER_FINSH;
                                 agnss_updata_finish_time = gaoz_get_systick();
                            }
                        }
                    }
                break;
                case AGNSS_SERVER_FINSH: 
                    if( gnss_status_get() != GPS_MODEL_POSI_OK ) 
                    {
                        if((sys_switch_state_get( SYS_KL15 ) == SYS_KL15_HIGH))
                        {
                           
                            agnss_data_timestamp_set( AGNSS_SLEEP_TIMESTAMP );

                           
                            if( agnss_server_data.sleep_timestamp > agnss_server_data.run_timestamp )
                            {   
                                if(( agnss_server_data.sleep_timestamp - agnss_server_data.run_timestamp ) > AGNDD_DATA_MAX_TIMESTAMP )
                                {
                              
                                    agnss_server_data.type = AGNSS_SERVER_INIT;
                                    agnss_server_data.couter = 0;
                                }
                                else
                                {
                                    if( gnss_agps_num_get() < GNSS_AGPS_NUM )
                                    {
                                        agnss_server_data.type = AGNSS_SERVER_UPDATA;
                                        agnss_server_data.couter = 0;       
                                    } 
                                    //如灌入成功后，仍然没有定位成功，则5min 再继续灌入
                                    if( pdPASS == sys_timestamp_delay(( uint32_t * )&agnss_updata_finish_time, (AGPS_DATA_UPDATA_TIME) ))
                                    {
                                        agnss_server_data.type = AGNSS_SERVER_UPDATA;
                                        agnss_server_data.couter = 0; 
                                    } 
                                }
                            }
                        }
                        else 
                        {
                            // log_debug_printf( ERROR_MODE,AGPS_MAN_NAME ,"AGNSS sys_switch_state_get( SYS_KL15 ) == SYS_KL15_LOW\r\n",0 );
                        }
                    }
                    else
                    {
                        agnss_server_data.again_timestamp = gaoz_get_systick();
                        agnss_server_data.couter = 0;
                    }
                break;

                case AGNSS_SERVER_ERR://错误1min后继续读 
                     log_debug_printf( ERROR_MODE,AGPS_MAN_NAME ,"AGNSS_SERVER_ERR \r\n",0);
                     if((sys_switch_state_get( SYS_KL15 ) == SYS_KL15_HIGH))
                     {
                        if( pdPASS == sys_timestamp_delay(( uint32_t * )&agnss_server_err_time, (AGPS_SERVER_ERR_TIME) ))
                        {
                            agnss_server_data.type = AGNSS_SERVER_INIT;
                            agnss_server_data.couter = 0;
                        }
                     }
                    
                    break;
                default:
                    break;
            }
        } 
        else
        {
            agnss_server_data.type = AGNSS_SERVER_FINSH;
            agnss_server_data.again_timestamp = gaoz_get_systick();
            agnss_updata_finish_time = gaoz_get_systick();
            agnss_server_data.couter = 0;
        }
        gaoz_task_sleep( 1000 );
    #endif
    }
}

